import * as fs from 'fs';
import * as path from 'path';

// 类型定义
interface SpeechRecognitionOptions {
  provider?: 'web' | 'baidu' | 'aliyun';
  language?: string;
  format?: string;
}

interface SpeechRecognitionResult {
  text: string;
  confidence: number;
  provider: string;
  language: string;
  note?: string;
}

interface LogEntry {
  timestamp: string;
  level: 'INFO' | 'ERROR' | 'DEBUG';
  service: string;
  message: string;
  data?: any;
}

interface BaiduAPIResult {
  result?: string[];
  confidence?: number;
}

interface AliyunAPIResult {
  result?: string;
  confidence?: number;
}

interface BaiduAPIParams {
  format: string;
  rate: number;
  channel: number;
  cuid: string;
  token: string;
  lan: string;
}

interface AliyunAPIParams {
  format: string;
  sample_rate: number;
  language_hints: string[];
}

interface SupportedLanguage {
  code: string;
  name: string;
}

interface ServiceStatus {
  defaultProvider: string;
  availableProviders: string[];
  supportedLanguages: SupportedLanguage[];
  tempDir: string;
  logFile: string;
}

type SpeechProvider = (audioData: string | Buffer, options: SpeechRecognitionOptions) => Promise<SpeechRecognitionResult>;

class SpeechService {
    private providers: Record<string, SpeechProvider>;
    private defaultProvider: string;
    private tempDir: string;
    private logDir: string;
    private logFile: string;

    constructor() {
        this.providers = {
            web: this.webSpeechAPI.bind(this),
            baidu: this.baiduSpeechAPI.bind(this),
            aliyun: this.aliyunSpeechAPI.bind(this)
        };
        
        this.defaultProvider = process.env.SPEECH_PROVIDER || 'web';
        this.tempDir = path.join(__dirname, '../../temp');
        this.logDir = path.join(__dirname, '../../../logs');
        this.logFile = path.join(this.logDir, 'server.log');
        
        // 确保临时目录和日志目录存在
        if (!fs.existsSync(this.tempDir)) {
            fs.mkdirSync(this.tempDir, { recursive: true });
        }
        if (!fs.existsSync(this.logDir)) {
            fs.mkdirSync(this.logDir, { recursive: true });
        }
        
        this.log('SpeechService初始化完成', { 
            defaultProvider: this.defaultProvider,
            tempDir: this.tempDir,
            availableProviders: Object.keys(this.providers)
        });
    }

    /**
     * 日志记录方法
     */
    private log(message: string, data: any = null, level: 'INFO' | 'ERROR' | 'DEBUG' = 'INFO'): void {
        const timestamp = new Date().toISOString();
        const logEntry: LogEntry = {
            timestamp,
            level,
            service: 'SpeechService',
            message,
            data
        };
        
        const logLine = `${timestamp} [${level}] [SpeechService] ${message}${data ? ' ' + JSON.stringify(data) : ''}\n`;
        
        // 输出到控制台
        if (level === 'ERROR') {
            console.error(logLine.trim());
        } else {
            console.log(logLine.trim());
        }
        
        // 异步写入文件
        fs.appendFile(this.logFile, logLine, (err) => {
            if (err) {
                console.error('写入日志文件失败:', err);
            }
        });
    }

    /**
     * 语音转文字主入口
     */
    async speechToText(audioData: string | Buffer, options: SpeechRecognitionOptions = {}): Promise<SpeechRecognitionResult> {
        const provider = options.provider || this.defaultProvider;
        const language = options.language || 'zh-CN';
        const requestId = `req_${Date.now()}_${Math.random().toString(36).substr(2, 6)}`;
        
        this.log('开始语音识别请求', {
            requestId,
            provider,
            language,
            audioDataSize: typeof audioData === 'string' ? audioData.length : (audioData ? audioData.length : 0),
            options
        });
        
        try {
            if (!this.providers[provider]) {
                throw new Error(`不支持的语音识别提供商: ${provider}`);
            }

            const startTime = Date.now();
            const result = await this.providers[provider](audioData, { language, ...options });
            const processingTime = Date.now() - startTime;
            
            this.log('语音识别完成', {
                requestId,
                provider,
                result: {
                    text: result.text,
                    confidence: result.confidence,
                    provider: result.provider,
                    language: result.language
                },
                processingTime: `${processingTime}ms`
            });
            
            return result;
            
        } catch (error) {
            const errorMessage = error instanceof Error ? error.message : 'Unknown error';
            this.log('语音识别失败', {
                requestId,
                provider,
                error: errorMessage,
                stack: error instanceof Error ? error.stack : undefined
            }, 'ERROR');
            
            // 如果当前提供商失败，尝试备用提供商
            if (provider !== 'web') {
                this.log('尝试使用备用语音识别服务', { requestId, fallbackProvider: 'web' });
                return await this.speechToText(audioData, { ...options, provider: 'web' });
            }
            
            throw error;
        }
    }

    /**
     * Web Speech API (客户端处理，服务端只做转发)
     */
    private async webSpeechAPI(audioData: string | Buffer, options: SpeechRecognitionOptions): Promise<SpeechRecognitionResult> {
        this.log('调用Web Speech API', {
            mode: '客户端语音识别模式',
            language: options.language || 'zh-CN',
            audioDataType: typeof audioData
        });
        
        const result: SpeechRecognitionResult = {
            text: '默认web识别',
            confidence: 0,
            provider: 'web',
            language: options.language || 'zh-CN',
            note: '语音识别在客户端进行，服务端不处理实际音频数据'
        };
        
        this.log('Web Speech API响应', { result });
        return result;
    }

    /**
     * 百度语音识别API
     */
    private async baiduSpeechAPI(audioData: string | Buffer, options: SpeechRecognitionOptions): Promise<SpeechRecognitionResult> {
        this.log('开始百度语音识别', { language: options.language });
        
        try {
            const appId = process.env.BAIDU_APP_ID;
            const apiKey = process.env.BAIDU_API_KEY;
            const secretKey = process.env.BAIDU_SECRET_KEY;
            
            if (!appId || !apiKey || !secretKey) {
                throw new Error('百度语音识别API配置不完整');
            }

            this.log('百度API配置检查通过', { appId: appId ? '已配置' : '未配置' });

            // 保存音频文件到临时目录
            const audioFile = await this.saveAudioFile(audioData, 'wav');
            this.log('音频文件保存成功', { audioFile });
            
            // 获取访问令牌
            const token = await this.getBaiduAccessToken(apiKey, secretKey);
            this.log('获取百度访问令牌', { tokenLength: token.length });
            
            // 调用百度API
            const apiParams: BaiduAPIParams = {
                format: 'wav',
                rate: 16000,
                channel: 1,
                cuid: 'smartinput',
                token: token,
                lan: this.mapLanguageToBaidu(options.language || 'zh-CN')
            };
            
            this.log('调用百度API', { params: apiParams });
            const result = await this.callBaiduAPI(audioFile, apiParams);

            // 清理临时文件
            fs.unlinkSync(audioFile);
            this.log('清理临时音频文件', { audioFile });

            const response: SpeechRecognitionResult = {
                text: result.result?.[0] || '',
                confidence: result.confidence || 0.8,
                provider: 'baidu',
                language: options.language || 'zh-CN'
            };
            
            this.log('百度语音识别成功', { response });
            return response;

        } catch (error) {
            const errorMessage = error instanceof Error ? error.message : 'Unknown error';
            this.log('百度语音识别失败', { 
                error: errorMessage,
                stack: error instanceof Error ? error.stack : undefined
            }, 'ERROR');
            throw new Error(`百度语音识别失败: ${errorMessage}`);
        }
    }

    /**
     * 阿里云语音识别API
     */
    private async aliyunSpeechAPI(audioData: string | Buffer, options: SpeechRecognitionOptions): Promise<SpeechRecognitionResult> {
        this.log('开始阿里云语音识别', { language: options.language });
        
        try {
            const accessKeyId = process.env.ALIYUN_ACCESS_KEY_ID;
            const accessKeySecret = process.env.ALIYUN_ACCESS_KEY_SECRET;
            
            if (!accessKeyId || !accessKeySecret) {
                throw new Error('阿里云语音识别API配置不完整');
            }

            this.log('阿里云API配置检查通过', { 
                accessKeyId: accessKeyId ? '已配置' : '未配置' 
            });

            // 保存音频文件到临时目录
            const audioFile = await this.saveAudioFile(audioData, 'wav');
            this.log('音频文件保存成功', { audioFile });
            
            // 调用阿里云API
            const apiParams: AliyunAPIParams = {
                format: 'wav',
                sample_rate: 16000,
                language_hints: [this.mapLanguageToAliyun(options.language || 'zh-CN')]
            };
            
            this.log('调用阿里云API', { params: apiParams });
            const result = await this.callAliyunAPI(audioFile, apiParams);

            // 清理临时文件
            fs.unlinkSync(audioFile);
            this.log('清理临时音频文件', { audioFile });

            const response: SpeechRecognitionResult = {
                text: result.result || '',
                confidence: result.confidence || 0.8,
                provider: 'aliyun',
                language: options.language || 'zh-CN'
            };
            
            this.log('阿里云语音识别成功', { response });
            return response;

        } catch (error) {
            const errorMessage = error instanceof Error ? error.message : 'Unknown error';
            this.log('阿里云语音识别失败', { 
                error: errorMessage,
                stack: error instanceof Error ? error.stack : undefined
            }, 'ERROR');
            throw new Error(`阿里云语音识别失败: ${errorMessage}`);
        }
    }

    /**
     * 保存音频文件到临时目录
     */
    private async saveAudioFile(audioData: string | Buffer, format: string = 'wav'): Promise<string> {
        const filename = `audio_${Date.now()}_${Math.random().toString(36).substr(2, 9)}.${format}`;
        const filepath = path.join(this.tempDir, filename);
        
        this.log('开始保存音频文件', { 
            filename, 
            format,
            dataType: typeof audioData,
            dataSize: typeof audioData === 'string' ? audioData.length : (audioData ? audioData.length : 0)
        });
        
        try {
            // 如果audioData是base64编码的，先解码
            let buffer: Buffer;
            if (typeof audioData === 'string') {
                // 移除data URL前缀
                const base64Data = audioData.replace(/^data:audio\/[a-z]+;base64,/, '');
                buffer = Buffer.from(base64Data, 'base64');
                this.log('解码base64音频数据', { 
                    originalLength: audioData.length,
                    base64Length: base64Data.length,
                    bufferSize: buffer.length 
                });
            } else {
                buffer = audioData;
            }
            
            fs.writeFileSync(filepath, buffer);
            
            const stats = fs.statSync(filepath);
            this.log('音频文件保存完成', { 
                filepath,
                fileSize: stats.size,
                created: stats.birthtime
            });
            
            return filepath;
        } catch (error) {
            const errorMessage = error instanceof Error ? error.message : 'Unknown error';
            this.log('保存音频文件失败', { 
                filepath,
                error: errorMessage 
            }, 'ERROR');
            throw error;
        }
    }

    /**
     * 获取百度访问令牌
     */
    private async getBaiduAccessToken(apiKey: string, secretKey: string): Promise<string> {
        this.log('开始获取百度访问令牌', { apiKey: apiKey.substring(0, 8) + '...' });
        
        try {
            // 实现百度API访问令牌获取
            // 这里需要实际的HTTP请求代码
            const mockToken = 'mock_access_token';
            
            this.log('百度访问令牌获取成功（模拟）', { tokenPreview: mockToken.substring(0, 10) + '...' });
            return mockToken;
        } catch (error) {
            const errorMessage = error instanceof Error ? error.message : 'Unknown error';
            this.log('获取百度访问令牌失败', { error: errorMessage }, 'ERROR');
            throw error;
        }
    }

    /**
     * 调用百度API
     */
    private async callBaiduAPI(audioFile: string, params: BaiduAPIParams): Promise<BaiduAPIResult> {
        this.log('开始调用百度语音识别API', { audioFile, params });
        
        try {
            // 实现百度语音识别API调用
            // 这里需要实际的HTTP请求代码
            const mockResult: BaiduAPIResult = {
                result: ['这是百度语音识别的模拟结果'],
                confidence: 0.9
            };
            
            this.log('百度API调用成功（模拟）', { result: mockResult });
            return mockResult;
        } catch (error) {
            const errorMessage = error instanceof Error ? error.message : 'Unknown error';
            this.log('调用百度API失败', { 
                audioFile,
                error: errorMessage 
            }, 'ERROR');
            throw error;
        }
    }

    /**
     * 调用阿里云API
     */
    private async callAliyunAPI(audioFile: string, params: AliyunAPIParams): Promise<AliyunAPIResult> {
        this.log('开始调用阿里云语音识别API', { audioFile, params });
        
        try {
            // 实现阿里云语音识别API调用
            // 这里需要实际的HTTP请求代码
            const mockResult: AliyunAPIResult = {
                result: '这是阿里云语音识别的模拟结果',
                confidence: 0.9
            };
            
            this.log('阿里云API调用成功（模拟）', { result: mockResult });
            return mockResult;
        } catch (error) {
            const errorMessage = error instanceof Error ? error.message : 'Unknown error';
            this.log('调用阿里云API失败', { 
                audioFile,
                error: errorMessage 
            }, 'ERROR');
            throw error;
        }
    }

    /**
     * 语言代码映射 - 百度
     */
    private mapLanguageToBaidu(language: string): string {
        const mapping: Record<string, string> = {
            'zh-CN': 'zh',
            'en-US': 'en',
            'zh-TW': 'zh'
        };
        const mapped = mapping[language] || 'zh';
        
        this.log('百度语言代码映射', { original: language, mapped });
        return mapped;
    }

    /**
     * 语言代码映射 - 阿里云
     */
    private mapLanguageToAliyun(language: string): string {
        const mapping: Record<string, string> = {
            'zh-CN': 'zh-cn',
            'en-US': 'en-us',
            'zh-TW': 'zh-tw'
        };
        const mapped = mapping[language] || 'zh-cn';
        
        this.log('阿里云语言代码映射', { original: language, mapped });
        return mapped;
    }

    /**
     * 清理临时文件
     */
    public cleanupTempFiles(maxAge: number = 60 * 60 * 1000): void { // 1小时
        this.log('开始清理临时文件', { maxAge: `${maxAge}ms`, tempDir: this.tempDir });
        
        try {
            const files = fs.readdirSync(this.tempDir);
            const now = Date.now();
            let cleanedCount = 0;
            
            files.forEach(file => {
                const filepath = path.join(this.tempDir, file);
                const stats = fs.statSync(filepath);
                
                if (now - stats.mtime.getTime() > maxAge) {
                    fs.unlinkSync(filepath);
                    cleanedCount++;
                    this.log('清理过期临时音频文件', { 
                        file,
                        age: `${Math.round((now - stats.mtime.getTime()) / 1000)}s`,
                        size: stats.size
                    });
                }
            });
            
            this.log('临时文件清理完成', { 
                totalFiles: files.length,
                cleanedFiles: cleanedCount,
                remainingFiles: files.length - cleanedCount
            });
            
        } catch (error) {
            const errorMessage = error instanceof Error ? error.message : 'Unknown error';
            this.log('清理临时文件失败', { 
                tempDir: this.tempDir,
                error: errorMessage 
            }, 'ERROR');
        }
    }

    /**
     * 获取支持的语言列表
     */
    public getSupportedLanguages(): SupportedLanguage[] {
        const languages: SupportedLanguage[] = [
            { code: 'zh-CN', name: '中文(简体)' },
            { code: 'zh-TW', name: '中文(繁体)' },
            { code: 'en-US', name: 'English (US)' },
            { code: 'ja-JP', name: '日本語' },
            { code: 'ko-KR', name: '한국어' }
        ];
        
        this.log('获取支持的语言列表', { languages });
        return languages;
    }

    /**
     * 获取服务状态
     */
    public getStatus(): ServiceStatus {
        const status: ServiceStatus = {
            defaultProvider: this.defaultProvider,
            availableProviders: Object.keys(this.providers),
            supportedLanguages: this.getSupportedLanguages(),
            tempDir: this.tempDir,
            logFile: this.logFile
        };
        
        this.log('获取服务状态', { status });
        return status;
    }
}

export default SpeechService;
